#include <iostream>
#include <unistd.h>
#include <vector>
#include <pthread.h>
#include "task.hpp"
#include <queue>
#include "Thread.hpp"
#include "Lock.hpp"
#define SIZE 5
using namespace std;
template <class T>
class ThreadPool
{
public:
    ThreadPool(int num = SIZE)
        :
          _capacity(num)
    {
        pthread_cond_init(&_cond, nullptr);
        pthread_mutex_init(&_mutex, nullptr);
    }

    ~ThreadPool()
    {
        for(int i=0;i<_capacity;i++)
        {
            _pool[i].join();
        }

        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mutex);
    }
    void Init()
    {
        for(int i=0;i<_capacity;i++)
        {
            _pool.push_back(Thread(i,pthreadRoutine,this));
        }
    }

    bool IsEmpty()
    {
        return _task.empty();
    }


    void  PthreadCondWait()
    {
        //cout<<"2"<<endl;
         pthread_cond_wait(&_cond,&_mutex);
        //cout<<"3"<<endl;
    }


    T PthreadTask()
    {
        T  t=_task.front();
        _task.pop();
        return t;
    }

    /*void PthreadMutexLock()
    {
        pthread_mutex_lock(&_mutex);
    }

    void PthreadMutexUnlock()
    {
        pthread_mutex_unlock(&_mutex);
    }*/


    pthread_mutex_t* PthreadLock()
    {
        return &_mutex;
    }
    static void pthreadRoutine(void *arg)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(arg);
        while(true)
        {
            T task;
        {
            MutexGuard m(tp->PthreadLock());
            //tp->PthreadMutexLock();    
            while (tp->IsEmpty())
            {
                tp->PthreadCondWait();
                //cout<<"1"<<endl;
            }
    
            task=tp->PthreadTask();
            //tp->PthreadMutexUnlock();
        }
            task();
            cout<<"thread handle done,the result is:"<<task.to_customer()<<endl;
        }
    }

    void start()
    {
        for (int i = 0; i < _capacity; i++)
        {
            _pool[i].Run();
        }
    }

    void  check()
    {
        for(auto& e:_pool)
        {
            cout<<e.name()<<endl;
        }

    }
    


    void push(const T& task)
    {
        MutexGuard m(&_mutex);
        //PthreadMutexLock();
        _task.push(task);
        pthread_cond_signal(&_cond);
        //PthreadMutexUnlock();
    }

private:
    vector<Thread> _pool;
    queue<T> _task;
    int _capacity;
    pthread_cond_t _cond;
    pthread_mutex_t _mutex;
};